--Controla la Entrada/Salida de datos, a memoria, ya sea por la UART
--o por el motorCordic

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity dmaModule is
	generic(
		DBIT:integer:=8; --ANCHO DE PALABRA EN LA UART
		W:integer:=37; --BITS NECESARIOS POR COORDENA
		WORDS:integer:=3; --WORDS NECESARIOS POR COORDENADA
		ABUS:integer:=18;  --BUS DE DIRECCION DE LA RAM
		DBUS: integer:=16 --BUS DE DATOS DE LA RAM
		);
	port(
		--GENERALES
		clk, reset: in std_logic;
		--ESTADO
		mode: out std_logic:='0'; -- '0'=UART/'1'=CORDIC
		--A LA UART
		rx_data: in std_logic_vector(DBIT-1 downto 0);
		rx_done_tick: in std_logic;
		--AL MOTOR CORDIC
		outX,outY,outZ: out std_logic_vector(WORDS*DBUS-1 downto 0);
		read_enable: in std_logic:='1';
		read: in std_logic;
		reset_vectors: in std_logic:='0';
		busy, vector_tick, restart: out std_logic;
		--AL CONTROLADOR DE MEMORIA
		mem,rw: out std_logic;
		sram_ready: in std_logic;
		sram_address: out std_logic_vector(ABUS-1 downto 0);
		sram_write_dbus: out std_logic_vector(DBUS-1 downto 0);
		sram_read_dbus: in std_logic_vector(DBUS-1 downto 0)
	    );
end entity;

architecture arch of dmaModule is
--	constant COORDW:integer:=integer(CEIL(real(W)/real(DBUS)));
--SALIDAS - PARSER
	signal is_digit, is_blank, is_esc,is_minus: std_logic;
--AUXILIAR - DIGIT COUNTER
	signal reset_digit_counter, enable_digit_counter: std_logic;
--SALIDA - DIGIT COUNTER
	signal digit_counter_match: std_logic;
--AUXILIARES - BCD2BIN
	signal enable_bcd2bin: std_logic;
--SALIDAS - BCD2BIN
	signal magnitude_bin:std_logic_vector(W-1 downto 0);
	signal sign_bin: std_logic;
	signal new_coord_flag: std_logic;
--SALIDAS - COMPLEMENTO A DOS 
	signal unsigned_bin: std_logic_vector(W-1 downto 0);
--AUXILIARES - ADDRESS COUNTER
	signal reset_address, notrestart: std_logic;
	signal enable_address_counter: std_logic;
--SALIDAS - ADDRESS COUNTER
	signal sram_address_aux: std_logic_vector(ABUS-1 downto 0);
--SALIDAS - MEMORY LOADER
	signal mem_load_crash: std_logic; --HACEMO' ALGO CON ESTO????
	signal mem_load: std_logic;

--AUXILIARES - MEMORY RW
	signal rw_aux, notrw_aux, esc_flag, is_esc_aux: std_logic;
--CONTROL DE DIRECCION
	signal max_address: std_logic_vector(ABUS-1 downto 0);
	signal address_overflow: std_logic;
--AUXILIARES - MEMORY READER
	signal read_enable_aux, mode_aux, notmode_aux: std_logic;  
  signal reset_memoryReader: std_logic; 
--SALIDAS - MEMORY READER
	signal mem_read_add_trig: std_logic;
	signal mem_read, busy_aux: std_logic; --MEM_READ

begin
--ASIGNACIONES A PUERTOS
rw<=rw_aux;
busy<=busy_aux;
mode<=mode_aux;
sram_address<=sram_address_aux;
restart<= not notrestart; --SI, NO LO ESCRIBI MAL.

PARSER0:entity work.ascii_parser(arch)
	port map (clk=>clk, reset=>reset,ascii => rx_data, rx_done_tick=>rx_done_tick,
			is_digit=>is_digit, is_blank=> is_blank, is_esc => is_esc, is_minus => is_minus);


reset_digit_counter<=(is_blank and rx_done_tick) OR reset;
enable_digit_counter<=rx_done_tick AND is_digit;

DIGIT_COUNTER0:entity work.mod_m_counter_stop_on_match(arch)
	generic map(N=>3,M=>5)	-- number of bits
	port map(clk=>clk, reset=>reset_digit_counter, enable=>enable_digit_counter,
		match => digit_counter_match, q => open);

enable_bcd2bin<=rx_done_tick and not digit_counter_match;

BCD2BIN0:entity work.bcd2binV2(arch)
        	generic map(W=>W)
		port map (clk=>clk, reset=>reset, bcd_in=>rx_data(3 downto 0),
			  dout=>magnitude_bin, new_output_flag => new_coord_flag,
			  sign => sign_bin, is_digit => is_digit, is_blank =>is_blank,
			  is_minus => is_minus, enable=>enable_bcd2bin);

TWOS0:entity work.twosComplement(arch)
	generic map(W=>W)
	port map(din=>magnitude_bin,dout=>unsigned_bin,sign=>sign_bin);

ADDCOUNT0:entity work.addressCounter(arch)
	generic map (ABUS=>ABUS)
	port map(clk=>clk, reset=>reset_address, enable=>enable_address_counter,
		address_out=>sram_address_aux);

--------------------------------------------------------------------------
--Reduccion de 16 bits... para WORD=1 este modulo es un cable
--------------------------------------------------------------------------

MEMLOAD0:entity work.memoryLoader(arch)
	generic map (W=>W, DBUS=>DBUS, WORDS=>WORDS)
	port map(clk=>clk, reset=>reset, crash_flag=>mem_load_crash,
			enable=>new_coord_flag, din=>unsigned_bin, sign_in=>sign_bin,
			mem_out=>mem_load, ready=>sram_ready,
			dout=>sram_write_dbus);

MEM_READ0:entity work.memoryReader(arch)
	generic map ( DBUS=>DBUS, WORDS=>1, BITS=>2)
	port map (clk => clk, reset => reset_memoryReader, addTrig => mem_read_add_trig,
			read=>read_enable_aux, outX => outX, outY=> outY, 
			outZ=>outZ, busy_out=>busy_aux, 
			vector_tick=>vector_tick, mem_out => mem_read,
			ready=>sram_ready,din=>sram_read_dbus);	


--Modo "free running"
read_enable_aux <= NOT busy_aux  AND read_enable AND mode_aux;

--Control de cambio de modo
--El latch espera que se desocupe la ram para cambiar de modo.
is_esc_aux<=is_esc AND rx_done_tick;
ESC_FFD0:entity work.FFD(arch)
		generic map(W => 1)
		port map(clk=>clk,reset=>reset, set=>is_esc_aux, prevQ(0)=>'1', Q(0)=>esc_flag);

--TODO:Explota en ficheros mal terminados (Que no terminan en \n<EOF>)
ESC_LATCH0:entity work.LATCH(arch)
		generic map(W => 1)
		port map(reset=>reset, set=>sram_ready, prevQ(0)=>esc_flag, Q(0)=>mode_aux);

--Cableado

--Este latch guarda la maxima dirección
notmode_aux <= not mode_aux;
	
ADD_MAX:entity work.LATCH(arch)
		generic map(W => ABUS)
		port map(reset=>reset, set=> notmode_aux, prevQ=> sram_address_aux, Q=> max_address);

--Todo: buscar como proteger contra desfasaje de coordenadas
--en archivos mal terminados. PODRIA REVISAR ADDRESS%3

COMPARADOR0: address_overflow<='0' when unsigned(sram_address_aux) < unsigned(max_address) else '1';

reset_address<= reset OR ((address_overflow OR reset_vectors) AND mode_aux );
reset_memoryReader<= reset OR (reset_vectors AND mode_aux);

MUX0: enable_address_counter<=mem_read_add_trig when mode_aux='1' else mem_load;
MUX1: mem<=mem_read when mode_aux='1' else mem_load;

RESTART0:entity work.FFD(arch)
		generic map(W => 1)
		port map(clk=>clk,reset=>address_overflow, set=>'1', prevQ(0)=>'1', Q(0)=>notrestart);
end arch;
